package com.pj.lib.auraServer.components.configuration;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.pj.lib.auraServer.app.Server;
import com.pj.lib.auraServer.app.ServerComponent;
import com.pj.lib.auraServer.app.listeners.OnAuraTypesChange;
import com.pj.lib.auraServer.components.DB.DB;
import com.pj.lib.auraServer.components.DB.tables.AuraType;
import com.pj.lib.auraServer.components.DB.tables.User;
import com.pj.lib.auraServer.components.connection.ClientThread;
import com.pj.lib.auraServer.exceptions.AuraServerException;
import com.pj.lib.aura.protocol.AuraProtocol;
import com.pj.lib.aura.connection.AuraTypeModel;
import com.pj.lib.auraServer.utils.Log;

public class AuraTypesComponent extends ServerComponent{

	public AuraTypesComponent(Server server) {
		super(server);
		
		addOnAuraTypeChange(new OnAuraTypesChange() {
			
			@Override
			public void updateAuraType(ClientThread ct, AuraTypeModel auraType,
					String code) {
				handleUpdateAuraType(ct, auraType, code);
			}
			
			@Override
			public void deleteAuraType(ClientThread ct, String code,
					String replacementCode) {
				handleDeleteAuraType(ct, code, replacementCode);
				
			}
			
			@Override
			public void addAuraTypes(ClientThread ct, AuraTypeModel[] auraTypes) {
				handleAddAuraType(ct, auraTypes);
				
			}

			@Override
			public void getAuraType(ClientThread ct, String code) {
				handleGetAuraType(ct, code);
				
			}
		});
	}

	

	protected void handleAddAuraType(ClientThread ct, AuraTypeModel[] auraTypes) {
		try {
			getDB().transactionStart();
			for(AuraTypeModel auraType : auraTypes) {
				((AuraType)getDB().getInstance(DB.INSTANCE_AURA_TYPE)).add(auraType);
			}
			getDB().transactionCommit();
			fireAuraTypesAddedEvent(auraTypes);
			ct.handleSendAddAuraTypes(true, null);
		} catch (SQLException e) {
			AuraServerException
			.handleExceptionInComponent(e, this, ct, AuraProtocol.ADD_AURA_TYPE, 
					true, getDB());
		} catch (AuraServerException e) {
			AuraServerException
			.handleExceptionInComponent(e, this, ct, AuraProtocol.ADD_AURA_TYPE, 
					true, getDB());
		}
		
		
	}

	protected void handleDeleteAuraType(ClientThread ct, String code,
			String replacementCode) {
		if(code == null || code.equals("") || replacementCode == null || replacementCode.equals("")) {
			ct.handleSendDeleteAuraTypes(false, "lib_code_or_replacement_code_is_null");
		} else {
			try {
				getDB().transactionStart();
			
				final List<Map<String, Object>> codeAuraType = getDB().getInstance(DB.INSTANCE_AURA_TYPE)
					.get(null, " " + AuraType.COLUMN_CODE + " = ?", new String[] {code}, null);
				final List<Map<String, Object>> replacementCodeAuraType = getDB().getInstance(DB.INSTANCE_AURA_TYPE)
					.get(null, " " + AuraType.COLUMN_CODE + " = ?", new String[] {replacementCode}, null);
				if(codeAuraType.size() == 1 && replacementCodeAuraType.size() == 1) {
					HashMap<String, Object> values = new HashMap<String, Object>();
					values.put(User.COLUMN_AURA_TYPE, replacementCode);
					//update
					getDB().getInstance(DB.INSTANCE_USER).update(values, 
							" " + User.COLUMN_AURA_TYPE + " = ? ", new String[] {code});
					
					//delete
					getDB().getInstance(DB.INSTANCE_AURA_TYPE).delete(AuraType.COLUMN_CODE + " = ?", new String[] {code});
					ct.handleSendDeleteAuraTypes(true, null);
					fireAuraTypeDeletedEvent(code);
				} else {
					ct.handleSendDeleteAuraTypes(false, "lib_there_are_no_such_aura_type");
				}
				getDB().transactionCommit();
			} catch (SQLException e) {
				AuraServerException
				.handleExceptionInComponent(e, this, ct, AuraProtocol.DELETE_AURA_TYPE, 
						true, getDB());
			} catch (AuraServerException e) {
				AuraServerException
				.handleExceptionInComponent(e, this, ct, AuraProtocol.DELETE_AURA_TYPE, 
						true, getDB());
			}
		}
	}

	protected void handleUpdateAuraType(ClientThread ct,
			AuraTypeModel auraType, String code) {
		if(auraType != null) {
			HashMap<String, Object> obj = new HashMap<String, Object>();
			obj.put(AuraType.COLUMN_NAME, auraType.name);
			obj.put(AuraType.COLUMN_RADIUS, auraType.radius);
			obj.put(AuraType.COLUMN_ACTION_ENTER_CODE, auraType.actionEnter);
			obj.put(AuraType.COLUMN_ACTION_EXIT_CODE, auraType.actionExit);
			obj.put(AuraType.COLUMN_ACTION_RETURN_CODE, auraType.actionReturn);
			obj.put(AuraType.COLUMN_ACTION_TEMP_LEAVE_CODE, auraType.actionTempLeave);
			obj.put(AuraType.COLUMN_LEAVING_TIME, auraType.leavingTime);
			
			try {
				getDB().getInstance(DB.INSTANCE_AURA_TYPE).
					update(obj, AuraType.COLUMN_CODE + " =  ?", new String[] {code});
				auraType.code = code;
				fireAuraTypeUpdatedEvent(auraType);
				ct.handleSendUpdateAuraTypes(true, null);
			} catch (SQLException e) {
				AuraServerException
				.handleExceptionInComponent(e, this, ct, AuraProtocol.UPDATE_AURA_TYPE, 
						true, getDB());
			} catch (AuraServerException e) {
				AuraServerException
				.handleExceptionInComponent(e, this, ct, AuraProtocol.UPDATE_AURA_TYPE, 
						true, getDB());
			}
		} else {
			ct.handleSendUpdateAuraTypes(false, "lib_aura_type_model_is_null");
		}
		
	}
	
	protected void handleGetAuraType(ClientThread ct, String code) {
		try {
			ArrayList<Map<String, Object>> types;
			if(code != null) {
				types = getDB().getInstance(DB.INSTANCE_AURA_TYPE).get(null, 
						AuraType.COLUMN_CODE + " = ?", new String[] {code}, null);
			} else {
				types = getDB().getInstance(DB.INSTANCE_AURA_TYPE).get(null, 
						null, null, null);
			}
			
			AuraTypeModel[] auraTypes = new AuraTypeModel[types.size()];
			AuraTypeModel model;
			int i = 0;
			for(Map<String, Object> type : types) {
				model = new AuraTypeModel();
				model.code = (String) type.get(AuraType.COLUMN_CODE);
				model.name = (String) type.get(AuraType.COLUMN_NAME);
				model.radius = (Integer) type.get(AuraType.COLUMN_RADIUS);
				model.actionEnter = (String) type.get(AuraType.COLUMN_ACTION_ENTER_CODE);
				model.actionExit = (String) type.get(AuraType.COLUMN_ACTION_EXIT_CODE);
				model.actionReturn = (String) type.get(AuraType.COLUMN_ACTION_RETURN_CODE);
				model.actionTempLeave = (String) type.get(AuraType.COLUMN_ACTION_TEMP_LEAVE_CODE);
				model.leavingTime = (Integer) type.get(AuraType.COLUMN_LEAVING_TIME);
				
				auraTypes[i++] = model;
				
			}
			ct.handleSendGetAuraType(true, null, auraTypes);
		} catch (SQLException e) {
			AuraServerException
			.handleExceptionInComponent(e, this, ct, AuraProtocol.GET_AURA_TYPE, 
					true, getDB());
		} catch (AuraServerException e) {
			AuraServerException
			.handleExceptionInComponent(e, this, ct, AuraProtocol.GET_AURA_TYPE, 
					true, getDB());
		}
	}

}
